import bpy

from ..ops.queue import RenderQueueRefresh
from . import icon
from .ui_list import AssetRender


def prefs():
    """反回插件属性
    """
    from ..utils import QueueUtils
    return QueueUtils.pref_()


def _get_blender_icon(icon_style):
    """反回图标名称

    Args:
        icon_style (类型或直接输入两个已设置的图标, optional): 图标风格,也可以自已设置图标id. Defaults to 'TRIA' | 'ARROW' | 'TRI' | (str, str).
    Returns:
        (str,str): _description_
    """
    icon_data = {
        'TRI': ('DISCLOSURE_TRI_DOWN', 'DISCLOSURE_TRI_RIGHT'),
        'TRIA': ('TRIA_DOWN', 'TRIA_RIGHT'),
        'SORT': ('SORT_ASC', 'SORT_DESC'),
        'ARROW': ('DOWNARROW_HLT', 'RIGHTARROW'),
        'CHECKBOX': ('CHECKBOX_HLT', 'CHECKBOX_DEHLT'),
        'RESTRICT_SELECT': ('RESTRICT_SELECT_OFF', 'RESTRICT_SELECT_ON'),
        'FAKE': ('FAKE_USER_OFF', 'FAKE_USER_ON'),
    }
    if icon_style in icon_data:
        return icon_data[icon_style]
    else:
        return icon_data['TRI']


def icon_two(bool_prop, style='CHECKBOX', custom_icon: tuple[str, str] = None, ) -> str:
    """输入一个布尔值,反回图标类型str
    Args:
        bool_prop (_type_): _description_
        custom_icon (tuple[str, str], optional): 输入两个自定义的图标名称,True反回前者. Defaults to None.
        style (str, optional): 图标的风格. Defaults to 'CHECKBOX'.
    Returns:
        str: 反回图标str
    """
    icon_true, icon_false = custom_icon if custom_icon else _get_blender_icon(
        style)
    return icon_true if bool_prop else icon_false


def draw_extend_ui(layout: bpy.types.UILayout, prop_name, label: str = None, align=True, alignment='LEFT',
                   default_extend=False, style='BOX', icon_style='ARROW', draw_func=None, draw_func_data={}):
    """
    使用bpy.context.window_manager来设置并存储属性
    if style == 'COLUMN':
        lay = layout.column()
    # "TRIA,ARROW,TRI""TRIA,ARROW,TRI"
    #: str("BOUND,BOX")
    enum in [‘EXPAND’, ‘LEFT’, ‘CENTER’, ‘RIGHT’], default LEFT

    draw_func(layout,**)
    draw_func_data{}
    """
    extend = bpy.context.window_manager.render_queue

    extend_prop_name = prop_name + '_extend'
    extend_bool = getattr(extend, extend_prop_name, None)
    if not isinstance(extend_bool, bool):
        # 如果没有则当场新建一个属性
        extend.default_bool_value = default_extend
        extend.add_ui_extend_bool_property = extend_prop_name
        extend_bool = getattr(extend, extend_prop_name)

    icon = icon_two(extend_bool, style=icon_style)

    lay = layout.column()
    if style == 'BOX':
        if extend_bool:
            col = layout.column(align=True)
            lay = col.box()
        else:
            col = layout
    else:
        col = lay = layout

    row = lay.row(align=align)

    row.alignment = alignment
    row.prop(extend, extend_prop_name,
             icon=icon,
             text='',
             toggle=1,
             icon_only=True,
             emboss=False
             )

    if draw_func:
        # 使用传入的绘制方法
        draw_func(layout=row, **draw_func_data)
    else:
        row.prop(extend, extend_prop_name,
                 text=label if label else extend_prop_name,
                 toggle=1,
                 expand=True,
                 emboss=False

                 )

    if style == 'BOX':
        if extend_bool:
            out_lay = col.column(align=True).box()
        else:
            out_lay = lay

    else:
        out_lay = lay

    return extend_bool, out_lay


class LeftRenderOut:
    layout: "bpy.types.UILayout"

    @staticmethod
    def draw_head(layout, prop_name):
        """绘制头部
        """
        pref = prefs()
        layout.emboss = 'NORMAL'
        layout.row(align=True).prop(pref, prop_name)

    @staticmethod
    def is_cycle() -> 'bool':
        """活动渲染引擎是cy"""
        return bpy.context.engine == 'CYCLES'

    @staticmethod
    def is_eevee() -> 'bool':
        """活动渲染引擎是ev"""
        return bpy.context.engine == 'BLENDER_EEVEE'

    # 绘制左边层
    def left_layout(self, context: bpy.context):
        """左侧层绘制"""

        layout = self.layout
        layout.use_property_split = False
        layout.use_property_decorate = False  # No animation.
        LeftRenderOut.draw_render_engine(layout)  # 引擎
        LeftRenderOut.draw_render_parameter(layout)  # 参数
        LeftRenderOut.draw_render_performance(layout)  # 性能
        LeftRenderOut.draw_render_format(layout)
        LeftRenderOut.draw_render_out(layout)  # 输出
        layout.separator(factor=50)

    @staticmethod
    def draw_render_parameter(layout: 'bpy.types.UILayout'):
        """绘制渲染参数
        采样
        透明
        降噪
        """
        scene = bpy.context.scene
        render = scene.render
        cycle = scene.cycles
        show, lay = draw_extend_ui(
            layout, 'render', '渲染参数', default_extend=False)
        pref = prefs()

        if show:
            LeftRenderOut.draw_render_sampling(lay)  # 采样
            LeftRenderOut.draw_noise(lay)
            LeftRenderOut.draw_color_management(lay)

            show, lay = draw_extend_ui(
                lay, 'use_film', '胶片',
                default_extend=False,
                draw_func=LeftRenderOut.draw_head,
                draw_func_data={'prop_name': 'use_film'})
            if show:
                lay.enabled = pref.use_film
                lay.prop(render, "film_transparent")

                lay.active = render.film_transparent

                col = lay.column()
                col.prop(cycle, "film_transparent_glass",
                         text="Transparent Glass")

                sub = col.column()
                sub.active = render.film_transparent and cycle.film_transparent_glass
                sub.prop(cycle, "film_transparent_roughness",
                         text="Roughness Threshold")

    @staticmethod
    def draw_render_performance(layout: 'bpy.types.UIList'):
        """绘制渲染性能相关项
        平铺
        色彩管理
        """
        scene = bpy.context.scene
        rd = scene.render
        cy = scene.cycles
        pref = prefs()

        show, lay = draw_extend_ui(
            layout, 'use_performance', '性能',
            default_extend=False,
            draw_func=LeftRenderOut.draw_head,
            draw_func_data={'prop_name': 'use_performance'})

        if show:
            lay.enabled = pref.use_performance
            col = lay.column()
            col.prop(rd, "threads_mode")
            sub = col.column(align=True)
            sub.enabled = rd.threads_mode == 'FIXED'
            sub.prop(rd, "threads")

            col = lay.column()
            col.prop(cy, "use_auto_tile")
            sub = col.column()
            sub.active = cy.use_auto_tile
            sub.prop(cy, "tile_size")

    @staticmethod
    def draw_render_engine(layout: 'bpy.types.UILayout'):
        """绘制渲染引擎"""

        context = bpy.context
        scene = context.scene
        render = scene.render
        pref = prefs()

        show, lay = draw_extend_ui(
            layout, 'use_engine', '渲染引擎',
            align=True,
            default_extend=False,
            draw_func=LeftRenderOut.draw_head,
            draw_func_data={'prop_name': 'use_engine'},
        )

        if show:
            lay.enabled = pref.use_engine
            if render.has_multiple_engines:
                lay.prop(render, "engine", text="Render Engine")

            if context.engine == 'CYCLES':
                from cycles import engine
                from cycles.ui import show_device_active, use_cpu
                cycle = scene.cycles

                col = lay.column()
                col.prop(cycle, "feature_set")

                col = lay.column()

                col.active = show_device_active(context)
                col.prop(cycle, "device")

                if engine.with_osl() and use_cpu(context):
                    col.prop(cycle, "shading_system")

    @staticmethod
    def draw_render_out(layout: 'bpy.types.UILayout'):
        """绘制渲染输出设置
        输出格式
        """

        context = bpy.context
        scene = context.scene
        render = scene.render
        image_settings = render.image_settings
        pref = prefs()

        show, lay = draw_extend_ui(
            layout, 'use_out', '使用格式', default_extend=False,
            draw_func=LeftRenderOut.draw_head, draw_func_data={
                'prop_name': 'use_out'}
        )

        if show:
            # lay.prop(render, "filepath", text="") # TODO 输出路径设置

            column = lay.column(align=True)

            col = column.column(heading="Saving")
            column.enabled = pref.use_out
            col.prop(render, "use_file_extension")
            col.prop(render, "use_render_cache")

            column.template_image_settings(
                image_settings, color_management=False)

            if not render.is_movie_format:
                col = column.column(heading="Image Sequence")
                col.prop(render, "use_overwrite")
                col.prop(render, "use_placeholder")

    @staticmethod
    def draw_render_format(layout: 'bpy.types.UILayout'):
        """绘制渲染输出格式
        """

        show, lay = draw_extend_ui(
            layout, 'use_format', '使用格式', default_extend=False,
            draw_func=LeftRenderOut.draw_head, draw_func_data={
                'prop_name': 'use_format'}
        )
        pref = prefs()

        if show:
            lay.enabled = pref.use_format
            context = bpy.context
            render = context.scene.render

            col = lay.column(align=True)

            row = col.row(align=True)
            row.prop(pref, 'use_scene_resolution', text='', toggle=-1)
            row.prop(pref, 'use_compositors_node', icon='NODE_COMPOSITING')

            co = col.column(align=True)
            co.active = pref.use_scene_resolution
            co.prop(render, "resolution_x", text="Resolution X")
            co.prop(render, "resolution_y", text="Y")

            row = col.row(align=True)
            row.prop(pref, 'use_resolution_percentage', text='', toggle=-1)
            row.prop(render, "resolution_percentage", text="%")

            col = lay.column(align=True)
            col.prop(render, "pixel_aspect_x", text="Aspect X")
            col.prop(render, "pixel_aspect_y", text="Y")

            col = lay.column(align=True)
            col.prop(render, "use_border")
            sub = col.column(align=True)
            sub.active = render.use_border
            sub.prop(render, "use_crop_to_border")
            col = lay.column(heading="Frame Rate")

            LeftRenderOut.draw_framerate(col, render)

    @staticmethod
    def draw_framerate(layout, rd):
        from bpy.types import RENDER_PT_format

        if RENDER_PT_format._preset_class is None:
            RENDER_PT_format._preset_class = bpy.types.RENDER_MT_framerate_presets

        args = rd.fps, rd.fps_base, RENDER_PT_format._preset_class.bl_label
        fps_label_text, show_framerate = RENDER_PT_format._draw_framerate_label(
            *args)

        layout.menu("RENDER_MT_framerate_presets", text=fps_label_text)

        if show_framerate:
            col = layout.column(align=True)
            col.prop(rd, "fps")
            col.prop(rd, "fps_base", text="Base")

    @staticmethod
    def draw_render_sampling(layout: 'bpy.types.UILayout'):
        """绘制渲染采样"""

        context = bpy.context
        scene = context.scene
        cycles = scene.cycles
        eevee = scene.eevee

        pref = prefs()

        show, lay = draw_extend_ui(
            layout, 'use_samples', '采样', default_extend=False,
            draw_func=LeftRenderOut.draw_head,
            draw_func_data={'prop_name': 'use_samples'}
        )

        if show:
            lay.enabled = pref.use_samples
            heading = lay.column(align=True, heading="Noise Threshold")
            row = heading.row(align=True)
            if LeftRenderOut.is_cycle():
                row.prop(cycles, "use_adaptive_sampling")
                sub = row.row()
                sub.active = cycles.use_adaptive_sampling
                sub.prop(cycles, "adaptive_threshold")

                col = lay.column(align=True)
                if cycles.use_adaptive_sampling:
                    col.prop(cycles, "samples", text=" Max Samples")
                    col.prop(cycles, "adaptive_min_samples",
                             text="Min Samples")
                else:
                    col.prop(cycles, "samples", text="Samples")
                col.prop(cycles, "time_limit")
            elif LeftRenderOut.is_eevee():
                row.prop(eevee, 'taa_samples')

    @staticmethod
    def draw_noise(layout: 'bpy.types.UILayout'):
        """绘制降噪参数"""
        context = bpy.context
        scene = context.scene
        eevee = scene.eevee
        cycle = scene.cycles
        pref = prefs()

        show, lay = draw_extend_ui(
            layout, 'use_noise', '降噪', default_extend=False,
            draw_func=LeftRenderOut.draw_head,
            draw_func_data={'prop_name': 'use_noise'}
        )

        if show:
            lay.enabled = pref.use_noise
            if LeftRenderOut.is_cycle():
                col = lay.column()
                col.active = cycle.use_denoising
                col.prop(cycle, "denoiser", text="Denoiser")
                col.prop(cycle, "denoising_input_passes", text="Passes")
                if cycle.denoiser == 'OPENIMAGEDENOISE':
                    col.prop(cycle, "denoising_prefilter", text="Prefilter")
            elif LeftRenderOut.is_eevee():
                col = lay.column(align=True)
                col.prop(eevee, "taa_render_samples", text="Render")
                col.prop(eevee, "taa_samples", text="Viewport")
                col = lay.column()
                col.prop(eevee, "use_taa_reprojection")

    @staticmethod
    def draw_color_management(layout: 'bpy.types.UILayout'):
        """绘制色彩管理
        TODO　曲线
        """

        context = bpy.context
        scene = context.scene
        view = scene.view_settings
        pref = prefs()

        show, lay = draw_extend_ui(
            layout, 'use_color_management', '使用色彩管理', default_extend=False,
            draw_func=LeftRenderOut.draw_head,
            draw_func_data={'prop_name': 'use_color_management'})

        if show:
            lay.enabled = pref.use_color_management
            flow = lay.grid_flow(row_major=True, columns=0,
                                 even_columns=False, even_rows=False, align=True)

            col = flow.column()
            col.prop(scene.display_settings, "display_device")

            col.separator()

            col.prop(view, "view_transform")
            col.prop(view, "look")

            col = flow.column()
            col.prop(view, "exposure")
            col.prop(view, "gamma")

            col.separator()

            col.prop(scene.sequencer_colorspace_settings,
                     "name", text="Sequencer")


class Queue:
    layout: 'bpy.types.UILayout'
    '''绘制渲染队列'''

    @staticmethod
    def draw_render_progress(layout: 'bpy.types.UILayout'):
        """绘制活动渲染项的渲染进度"""
        pref = prefs()
        now = pref.render_in_item

        if now:
            items = now.read_render_progress_strings

            if items:
                layout.label(text=now.from_set_get_cn_progress(items[-1]))

            if items and pref.show_detailed_render_info:
                '''显示详情'''
                for item in items[::-1]:
                    layout.label(text=item)

    @staticmethod
    def draw_sum_render_progress(layout: 'bpy.types.UILayout'):
        """绘制总渲染进度"""
        pref = prefs()
        if pref.show_render_sum_progress:
            now = pref.render_in_item
            if now:
                layout.prop(now, 'render_sum_progress', slider=True)

    @staticmethod
    def draw_render_queue(layout: 'bpy.types.UILayout'):
        """绘制渲染队列"""
        pref = prefs()
        col = layout.column(align=True)
        sp = col.split(factor=pref.split_queue_list, align=True)

        sp.template_list(AssetRender.bl_idname, '',
                         pref, 'render_items',
                         pref, 'active_index',
                         rows=15 if pref.render_items else 5,
                         )

        Queue.draw_render_info(sp)
        Queue.draw_render_progress(col)

    @staticmethod
    def draw_render_info(layout: 'bpy.types.UILayout'):
        """绘制渲染队列信息"""
        pref = prefs()

        col = layout.column()
        next_item = pref.render_next_item
        next_name = next_item.name if next_item else 'NONE'

        now = pref.render_in_item
        n = now.name if now else 'NONE'

        box = col.box()
        box.label(text=f'当前渲染项:{n}')
        box.label(text=f'下一渲染项:{next_name}')
        box.separator()
        box.label(text=f'待渲染项{len(pref.render_not_items)}')
        box.label(text=f'渲染队列中{len(pref.render_in_queue_items)}')
        box.label(text=f'渲染完成项{len(pref.render_finished_items)}')
        box.label(text=f'渲染错误项{len(pref.render_error_items)}')
        Queue.draw_sum_render_progress(box)

        col.separator(factor=10)

        co = col.column()
        co.scale_y = 1.5
        from ..ops.queue import RenderQueueClear, RenderQueueStart, RenderQueueAdd, RenderQueueStop
        from ..ui.menu import QueueMenu
        co.operator(RenderQueueClear.bl_idname)
        co.operator(RenderQueueStart.bl_idname)
        co.operator(RenderQueueStop.bl_idname)
        co.operator(RenderQueueAdd.bl_idname)

        path = bpy.context.scene.render.filepath
        row = co.row(align=True)
        row.operator('wm.path_open', icon='FILEBROWSER').filepath = path
        row.operator(RenderQueueRefresh.bl_idname, text="", icon="FILE_REFRESH")

        row.menu(QueueMenu.bl_idname)
        Queue.draw_rendered_image(co)

    @staticmethod
    def draw_rendered_image(layout: 'bpy.types.UILayout'):
        """绘制已渲染完成图像
        如果活动项队列已完成渲染将会加载渲染完成的图片"""
        import os
        pref = prefs()
        render = pref.active_render
        path = render and render.rendered_image_file_path

        is_show_image = path and os.path.isfile(path)
        if is_show_image:
            layout.template_icon(icon.get(path), scale=8)

    def left_bottom_layout(self: bpy.types.Panel, context: bpy.context):
        """左下角那一小块,只有底栏不显示才会显示
        左边底部层
        """

        layout = self.layout
        column = layout.column()
        column.alert = True
        AssetLayout.exit_button(layout)

    layout: 'bpy.types.UILayout'

    # 绘制右边层
    def right_layout(self: bpy.types.Panel, context: bpy.context):
        layout = self.layout
        Queue.draw_render_queue(layout)


class AssetLayout(Queue,
                  LeftRenderOut,
                  ):
    """通过更改偏好设置的绘制方法来实现重新绘制偏好设置
    绘制资产层
    """
    layout: 'bpy.types.UILayout'

    @staticmethod
    def render_master(layout: 'bpy.types.UILayout'):
        pref = prefs()
        if pref.enabled_render_master:
            layout.operator('wm.popup_render_window')

    # 底部绘制层

    def bottom_layout(self: bpy.types.Panel, context: bpy.context):
        layout = self.layout
        row = layout.row()
        ro = row.row(align=True)
        ro.scale_x = 1.5

        AssetLayout.exit_button(row.row())

    @staticmethod
    def exit_button(layout: 'bpy.types.UILayout') -> 'bpy.types.UILayout.operator':
        """退出按钮
        """
        from ..ops.queue import SwitchQueueUI
        layout.alert = True
        return layout.operator(SwitchQueueUI.bl_idname,
                               text='退出',
                               icon='PANEL_CLOSE'
                               )
